/*
 *  Copyright 2005 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.taglib.core.html;

import com.blandware.atleap.webapp.util.core.WebappConstants;
import com.blandware.atleap.webapp.util.core.WebappUtil;
import org.apache.commons.validator.GenericValidator;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.taglib.TagUtils;
import org.apache.struts.taglib.html.Constants;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.RequestUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;


/**
 * <p>Tag for 'form' element. Originally taken from Struts FormTag.</p>
 * <p/>
 * Following attributes are supported:
 * <ul>
 * <li>
 * <b>action</b> - the URL of action that will process the form data (required)
 * </li>
 * <li>
 * <b>enctype</b> - the content encoding used when submitting this form
 * </li>
 * <li>
 * <b>focus</b> - the name of form's field which will get focus
 * </li>
 * <li>
 * <b>method</b> - method that will be used to submit form
 * </li>
 * <li>
 * <b>onreset</b> - script handler that is called when reset occurs
 * </li>
 * <li>
 * <b>onsubmit</b> - script handler that is called when form is submitted
 * </li>
 * <li>
 * <b>style</b> - CSS that will be applied to this form
 * </li>
 * <li>
 * <b>styleClass</b> - 'class' that will be assigned to this form
 * </li>
 * <li>
 * <b>tagId</b> - 'id' that will be assigned to this form
 * </li>
 * <li>
 * <b>target</b> - window 'target' that will be assigned to this form
 * </li>
 * <li>
 * <b>acceptCharset</b> - list of charsets that are acceptable
 * </li>
 * <li>
 * <b>focusIndex</b> - index of the focus field
 * </li>
 * <li>
 * <b>scriptLanguage</b> - whether or not the focus script's &lt;script&gt;
 * element will include the language attribute.
 * </li>
 * <li>
 * <b>validateOnSubmit</b> - whether or not to validate the form when submitting.
 * This can be 'true' or 'false', default is 'true'.
 * </li>
 * <li>
 * <b>disableButtonsOnSubmit</b> - whether to disable all buttons (actually 'submits')
 * after submittion to prevent multiple submittion. This can be 'true' or 'false',
 * default is 'true'.
 * </li>
 * </ul>
 * </p>
 * <p>
 * If something is returned from <b>onsubmit</b> code supplied by user, no
 * additional validation or form disable is assigned to form on-submit event.
 * </p>
 * <p/>
 * <p><a href="FormTag.java.html"><i>View source</i></a></p>
 *
 * @author Roman Puchkovskiy <a href="mailto:roman.puchkovskiy@blandware.com">
 *         &lt;roman.puchkovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.9 $ $Date: 2008/06/24 06:39:08 $
 * @jsp.tag name="form"
 * body-content="scriptless"
 * @see org.apache.struts.taglib.html.FormTag
 */
public class FormTag extends SimpleTagSupport {
	/**
	 * The action URL to which this form should be submitted, if any.
	 */
	protected String action = null;

	/**
	 * The module configuration for our module.
	 */
	protected ModuleConfig moduleConfig = null;

	/**
	 * The content encoding to be used on a POST submit.
	 */
	protected String enctype = null;

	/**
	 * The name of the field to receive focus, if any.
	 */
	protected String focus = null;

	/**
	 * The index in the focus field array to receive focus.  This only applies if the field
	 * given in the focus attribute is actually an array of fields.  This allows a specific
	 * field in a radio button array to receive focus while still allowing indexed field
	 * names like "myRadioButtonField[1]" to be passed in the focus attribute.
	 */
	protected String focusIndex = null;

	/**
	 * The line ending string.
	 */
	protected static String lineEnd = System.getProperty("line.separator");

	/**
	 * The ActionMapping defining where we will be submitting this form
	 */
	protected ActionMapping mapping = null;

	/**
	 * The message resources for this package.
	 */
	protected static MessageResources messages =
			MessageResources.getMessageResources(Constants.Package + ".LocalStrings");

	/**
	 * The request method used when submitting this form.
	 */
	protected String method = null;

	/**
	 * The onReset event script.
	 */
	protected String onreset = null;

	/**
	 * The onSubmit event script.
	 */
	protected String onsubmit = null;

	/**
	 * Include language attribute in the focus script's &lt;script&gt; element.  This
	 * property is ignored in XHTML mode.
	 */
	protected Boolean scriptLanguage = Boolean.TRUE;

	/**
	 * The ActionServlet instance we are associated with (so that we can
	 * initialize the <code>servlet</code> property on any form bean that
	 * we create).
	 */
	protected ActionServlet servlet = null;

	/**
	 * The style attribute associated with this tag.
	 */
	protected String style = null;

	/**
	 * The style class associated with this tag.
	 */
	protected String styleClass = null;

	/**
	 * The identifier associated with this tag.
	 */
	protected String tagId = null;

	/**
	 * The window target.
	 */
	protected String target = null;

	/**
	 * The name of the form bean to (create and) use. This is either the same
	 * as the 'name' attribute, if that was specified, or is obtained from the
	 * associated <code>ActionMapping</code> otherwise.
	 */
	protected String beanName = null;

	/**
	 * The scope of the form bean to (create and) use. This is either the same
	 * as the 'scope' attribute, if that was specified, or is obtained from the
	 * associated <code>ActionMapping</code> otherwise.
	 */
	protected String beanScope = null;

	/**
	 * The type of the form bean to (create and) use. This is either the same
	 * as the 'type' attribute, if that was specified, or is obtained from the
	 * associated <code>ActionMapping</code> otherwise.
	 */
	protected String beanType = null;

	/**
	 * The list of character encodings for input data that the server should
	 * accept.
	 */
	protected String acceptCharset = null;

	protected PageContext pageContext = null;

	/**
	 * Whether to validate this form on submit
	 */
	protected Boolean validateOnSubmit = Boolean.TRUE;

	/**
	 * Whether to disable all buttons on this form on submit
	 */
	protected Boolean disableButtonsOnSubmit = Boolean.TRUE;

	/**
	 * Return the name of the form bean corresponding to this tag. There is
	 * no corresponding setter method; this method exists so that the nested
	 * tag classes can obtain the actual bean name derived from other
	 * attributes of the tag.
	 *
	 * @return name of the form bean
	 */
	public String getBeanName() {

		return beanName;

	}

	/**
	 * Returns the action URL to which this form should be submitted.
	 *
	 * @return action URL
	 * @jsp.attribute required="true"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Action URL"
	 */
	public String getAction() {

		return (this.action);

	}

	/**
	 * Sets the action URL to which this form should be submitted.
	 *
	 * @param action The new action URL
	 */
	public void setAction(String action) {

		this.action = action;

	}

	/**
	 * Returns the content encoding used when submitting this form.
	 *
	 * @return content encoding
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Content encoding used when submitting this form"
	 */
	public String getEnctype() {

		return (this.enctype);

	}

	/**
	 * Sets the content encoding used when submitting this form.
	 *
	 * @param enctype The new content encoding
	 */
	public void setEnctype(String enctype) {

		this.enctype = enctype;

	}

	/**
	 * Returns the focus field name for this form.
	 *
	 * @return focus field name
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The focus field name for this form"
	 */
	public String getFocus() {

		return (this.focus);

	}

	/**
	 * Sets the focus field name for this form.
	 *
	 * @param focus The new focus field name
	 */
	public void setFocus(String focus) {

		this.focus = focus;

	}

	/**
	 * Returns the request method used when submitting this form.
	 *
	 * @return request method
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The request method used when submitting this form"
	 */
	public String getMethod() {

		return (this.method);

	}

	/**
	 * Sets the request method used when submitting this form.
	 *
	 * @param method The new request method
	 */
	public void setMethod(String method) {

		this.method = method;

	}

	/**
	 * Returns the onReset event script.
	 *
	 * @return onReset handler
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The onReset event script"
	 */
	public String getOnreset() {

		return (this.onreset);

	}

	/**
	 * Sets the onReset event script.
	 *
	 * @param onReset The new event script
	 */
	public void setOnreset(String onReset) {

		this.onreset = onReset;

	}

	/**
	 * Returns the onSubmit event script.
	 *
	 * @return onSubmit handler
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The onSubmit event script"
	 */
	public String getOnsubmit() {

		return (this.onsubmit);

	}

	/**
	 * Sets the onSubmit event script.
	 *
	 * @param onSubmit The new event script
	 */
	public void setOnsubmit(String onSubmit) {

		this.onsubmit = onSubmit;

	}

	/**
	 * Returns the style attribute for this tag.
	 *
	 * @return style attribute
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The style attribute for this tag"
	 */
	public String getStyle() {

		return (this.style);

	}

	/**
	 * Sets the style attribute for this tag.
	 *
	 * @param style The new style attribute
	 */
	public void setStyle(String style) {

		this.style = style;

	}

	/**
	 * Returns the style class for this tag.
	 *
	 * @return style class
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The style class for  this tag"
	 */
	public String getStyleClass() {

		return (this.styleClass);

	}

	/**
	 * Sets the style class for this tag.
	 *
	 * @param styleClass The new style class
	 */
	public void setStyleClass(String styleClass) {

		this.styleClass = styleClass;

	}

	/**
	 * Returns the id for this tag.
	 *
	 * @return id
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The id for this tag"
	 */
	public String getTagId() {

		return (this.tagId);

	}

    /**
     * Sets tag ID.
     *
     * @param tagId ID to set
     */
    public void setTagId(String tagId) {
        this.tagId = tagId;
    }

	/**
	 * Sets the id for this tag.
	 *
	 * @param tagId The new id
	 */
	public void setStyleId(String tagId) {

		this.tagId = tagId;

	}

	/**
	 * Returns the window target.
	 *
	 * @return target
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The window target"
	 */
	public String getTarget() {

		return (this.target);

	}

	/**
	 * Sets the window target.
	 *
	 * @param target The new window target
	 */
	public void setTarget(String target) {

		this.target = target;

	}

	/**
	 * Returns the list of character encodings accepted.
	 *
	 * @return list of encodings
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The list of character encodings accepted"
	 */
	public String getAcceptCharset() {

		return acceptCharset;

	}

	/**
	 * Sets the list of character encodings accepted.
	 *
	 * @param acceptCharset The list of character encodings
	 */
	public void setAcceptCharset(String acceptCharset) {

		this.acceptCharset = acceptCharset;

	}

	/**
	 * Returns the focus index (that is the index of focus field)
	 *
	 * @return focus index
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The focus index"
	 */
	public String getFocusIndex() {
		return focusIndex;
	}

	/**
	 * Sets the focusIndex.
	 *
	 * @param focusIndex The focusIndex to set
	 */
	public void setFocusIndex(String focusIndex) {
		this.focusIndex = focusIndex;
	}

	/**
	 * Gets whether or not the focus script's &lt;script&gt; element will include the
	 * language attribute.
	 *
	 * @return <code>Boolean.TRUE</code> if language attribute will be included.
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Whether or not the focus script's script element will include the language attribute"
	 */
	public Boolean getScriptLanguage() {
		return this.scriptLanguage;
	}

	/**
	 * Sets whether or not the focus script's &lt;script&gt; element will include the
	 * language attribute.
	 */
	public void setScriptLanguage(Boolean scriptLanguage) {
		this.scriptLanguage = scriptLanguage;
	}

	/**
	 * Gets whether form need to be validated on submit
	 *
	 * @return <code>Boolean.TRUE</code> if form will be validated
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Whether or not the form will be validated"
	 */
	public Boolean getValidateOnSubmit() {
		return validateOnSubmit;
	}

	/**
	 * Sets whether form need to be validated on submit
	 *
	 * @param validateOnSubmit if <code>Boolean.TRUE</code>, the form will be
	 *                         validated on submit
	 */
	public void setValidateOnSubmit(Boolean validateOnSubmit) {
		this.validateOnSubmit = validateOnSubmit;
	}

	/**
	 * Gets whether all form buttons need to be disabled on submit
	 *
	 * @return <code>Boolean.TRUE</code> if buttons must be disabled
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Whether or not the form buttons will be disabled on submit"
	 */
	public Boolean getDisableButtonsOnSubmit() {
		return disableButtonsOnSubmit;
	}

	/**
	 * Sets whether all form buttons need to be disabled on submit
	 *
	 * @param disableButtonsOnSubmit if <code>Boolean.TRUE</code>, buttons will be
	 *                               disabled on submit
	 */
	public void setDisableButtonsOnSubmit(Boolean disableButtonsOnSubmit) {
		this.disableButtonsOnSubmit = disableButtonsOnSubmit;
	}

	/**
	 * Locates or creates the bean associated with our form.
	 *
	 * @throws JspException
	 */
	protected void initFormBean() throws JspException {
		int scope = PageContext.SESSION_SCOPE;
		if ( "request".equalsIgnoreCase(beanScope) ) {
			scope = PageContext.REQUEST_SCOPE;
		}

		Object bean = pageContext.getAttribute(beanName, scope);
		if ( bean == null ) {
			// New and improved - use the values from the action mapping
			bean =
					RequestUtils.createActionForm(
							(HttpServletRequest) pageContext.getRequest(),
							mapping,
							moduleConfig,
							servlet);
			if ( bean instanceof ActionForm ) {
				((ActionForm) bean).reset(mapping, (HttpServletRequest) pageContext.getRequest());
			}
			if ( bean == null ) {
				throw new JspException(messages.getMessage("formTag.create", beanType));
			}
			pageContext.setAttribute(beanName, bean, scope);
		}
		pageContext.setAttribute(Constants.BEAN_KEY, bean, PageContext.REQUEST_SCOPE);
	}

	/**
	 * Generates the opening <code>&lt;form&gt;</code> element with appropriate
	 * attributes.
	 */
	protected String renderFormStartElement() {

		StringBuffer results = new StringBuffer("<form");

		// render attributes
		renderName(results);
		renderAttribute(results, "method", getMethod() == null ? "post" : getMethod());
		renderAction(results);
		renderAttribute(results, "accept-charset", getAcceptCharset());
		renderAttribute(results, "class", getStyleClass());
		renderAttribute(results, "enctype", getEnctype());
		renderAttribute(results, "onreset", getOnreset());
		renderAttribute(results, "onsubmit", getOnsubmit());
		renderAttribute(results, "style", getStyle());
		renderAttribute(results, "id", getTagId());
		renderAttribute(results, "target", getTarget());

		// Hook for additional attributes
		renderOtherAttributes(results);

		results.append(">");
		return results.toString();
	}

	/**
	 * Renders the name attribute
	 *
	 * @param results buffer where to write to
	 */
	protected void renderName(StringBuffer results) {
		results.append(" name=\"");
		results.append(beanName);
		results.append("\"");
	}

	/**
	 * Renders the action attribute
	 *
	 * @param results buffer where to write to
	 */
	protected void renderAction(StringBuffer results) {

		HttpServletResponse response =
				(HttpServletResponse) pageContext.getResponse();

		results.append(" action=\"");
		results.append(response.encodeURL(
				WebappUtil.getActionMappingURL(action, null, (HttpServletRequest) pageContext.getRequest(),
						WebappConstants.URL_TYPE_DOMAIN_RELATIVE)));

		results.append("\"");
	}

	/**
	 * 'Hook' to enable this tag to be extended and
	 * additional attributes added.
	 *
	 * @param results buffer where to write to
	 */
	protected void renderOtherAttributes(StringBuffer results) {
	}

	/**
	 * Generates a hidden input field with token information, if any.
	 *
	 * @return A hidden input field containing the token.
	 */
	protected String renderToken() {
		StringBuffer results = new StringBuffer();
		HttpSession session = pageContext.getSession();

		if ( session != null ) {
			String token =
					(String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);

			if ( token != null ) {
				results.append("<input type=\"hidden\" name=\"");
				results.append(Constants.TOKEN_KEY);
				results.append("\" value=\"");
				results.append(token);
				if ( this.isXhtml() ) {
					results.append("\" />");
				} else {
					results.append("\">");
				}
			}
		}

		return results.toString();
	}

	/**
	 * Renders attribute="value" if not null
	 *
	 * @param results   buffer where to write to
	 * @param attribute attribute name
	 * @param value     attribute value
	 */
	protected void renderAttribute(StringBuffer results, String attribute, String value) {
		if ( value != null ) {
			results.append(" ");
			results.append(attribute);
			results.append("=\"");
			results.append(value);
			results.append("\"");
		}
	}

	/**
	 * Renders the form
	 *
	 * @throws JspException
	 * @throws IOException
	 */
	public void doTag() throws JspException, IOException {
		pageContext = (PageContext) getJspContext();
		if ( scriptLanguage == null ) {
			scriptLanguage = Boolean.TRUE;
		}

		if ( validateOnSubmit == null ) {
			validateOnSubmit = Boolean.TRUE;
		}
		if ( disableButtonsOnSubmit == null ) {
			disableButtonsOnSubmit = Boolean.TRUE;
		}

		// Look up the form bean name, scope, and type if necessary
		this.lookup();

		// If there's already 'return' in onsubmit, we don't touch it. Otherwise
		// we should probably add validation and/or disable buttons
		// TODO: improve: 'return's in literals shouldn't be considered
		boolean isReturnInOnsubmit = onsubmit != null && onsubmit.matches("(.*)\\breturn\\b(.*)");
		if ( !isReturnInOnsubmit ) {
			if ( onsubmit == null ) {
				onsubmit = "";
			}
			if ( validateOnSubmit.booleanValue() && disableButtonsOnSubmit.booleanValue() ) {
				onsubmit = onsubmit + "var isValidForm = validateForm(this);"
						+ "disableButtons(this, isValidForm);"
						+ "return isValidForm;";
			} else if ( validateOnSubmit.booleanValue() ) {
				onsubmit = onsubmit + "return validateForm(this);";
			} else if ( disableButtonsOnSubmit.booleanValue() ) {
				onsubmit = onsubmit + "disableButtons(this, true);";
			}
		}
		if ( GenericValidator.isBlankOrNull(onsubmit) ) {
			// to prevent output of empty onsubmit
			onsubmit = null;
		}

		// Create an appropriate "form" element based on our parameters
		StringBuffer results = new StringBuffer();

		results.append(this.renderFormStartElement());

		results.append(this.renderToken());

        // Writing all we generated BEFORE tag body 
        JspWriter writer = pageContext.getOut();
        try {
            writer.print(results);
        } catch (IOException e) {
            throw new JspException(messages.getMessage("common.io", e.toString()));
        }
        results = new StringBuffer();

        // Store this tag itself as a page attribute
		pageContext.setAttribute(WebappConstants.FORM_KEY, this, PageContext.REQUEST_SCOPE);

		this.initFormBean();

		// Get body and append its connent
        JspFragment body = getJspBody();
		if ( body != null ) {
			body.invoke(null);
		}

		// Remove the page scope attributes we created
		pageContext.removeAttribute(Constants.BEAN_KEY, PageContext.REQUEST_SCOPE);
		pageContext.removeAttribute(WebappConstants.FORM_KEY, PageContext.REQUEST_SCOPE);

		// Render a tag representing the end of our current form
		results.append("</form>");

		// Render JavaScript to set the input focus if required
		if ( this.focus != null ) {
			results.append(this.renderFocusJavascript());
		}

		// Print this value to our output writer
		try {
			writer.print(results.toString());
		} catch ( IOException e ) {
			throw new JspException(messages.getMessage("common.io", e.toString()));
		}
	}

	/**
	 * Generates javascript to set the initial focus to the form element given in the
	 * tag's "focus" attribute.
	 */
	protected String renderFocusJavascript() {
		StringBuffer results = new StringBuffer();

		results.append(lineEnd);
		results.append("<script type=\"text/javascript\"");
		if ( !this.isXhtml() && this.scriptLanguage.booleanValue() ) {
			results.append(" language=\"JavaScript\"");
		}
		results.append(">");
		results.append(lineEnd);

		// xhtml script content shouldn't use the browser hiding trick
		if ( !this.isXhtml() ) {
			results.append("  <!--");
			results.append(lineEnd);
		}

		// Construct the control name that will receive focus.
		// This does not include any index.
		StringBuffer focusControl = new StringBuffer("document.forms[\"");
		focusControl.append(beanName);
		focusControl.append("\"].elements[\"");
		focusControl.append(this.focus);
		focusControl.append("\"]");

		results.append("  var focusControl = ");
		results.append(focusControl.toString());
		results.append(";");
		results.append(lineEnd);
		results.append(lineEnd);

		results.append("  if (focusControl.type != \"hidden\" && !focusControl.disabled) {");
		results.append(lineEnd);

		// Construct the index if needed and insert into focus statement
		String index = "";
		if ( this.focusIndex != null ) {
			StringBuffer sb = new StringBuffer("[");
			sb.append(this.focusIndex);
			sb.append("]");
			index = sb.toString();
		}
		results.append("     focusControl");
		results.append(index);
		results.append(".focus();");
		results.append(lineEnd);

		results.append("  }");
		results.append(lineEnd);

		if ( !this.isXhtml() ) {
			results.append("  // -->");
			results.append(lineEnd);
		}

		results.append("</script>");
		results.append(lineEnd);
		return results.toString();
	}

	/**
	 * Looks up values for the <code>name</code>, <code>scope</code>, and
	 * <code>type</code> properties if necessary.
	 *
	 * @throws JspException if a required value cannot be looked up
	 */
	protected void lookup() throws JspException {

		// Look up the module configuration information we need
		moduleConfig = TagUtils.getInstance().getModuleConfig(pageContext);

		if ( moduleConfig == null ) {
			JspException e = new JspException(messages.getMessage("formTag.collections"));
			pageContext.setAttribute(Globals.EXCEPTION_KEY, e, PageContext.REQUEST_SCOPE);
			throw e;
		}
		servlet =
				(ActionServlet) pageContext.getServletContext().getAttribute(
						Globals.ACTION_SERVLET_KEY);

		// Look up the action mapping we will be submitting to
		String mappingName = TagUtils.getInstance().getActionMappingName(action);
		mapping = (ActionMapping) moduleConfig.findActionConfig(mappingName);
		if ( mapping == null ) {
			JspException e = new JspException(messages.getMessage("formTag.mapping", mappingName));
			pageContext.setAttribute(Globals.EXCEPTION_KEY, e, PageContext.REQUEST_SCOPE);
			throw e;
		}

		// Look up the form bean definition
		FormBeanConfig formBeanConfig = moduleConfig.findFormBeanConfig(mapping.getName());
		if ( formBeanConfig == null ) {
			JspException e =
					new JspException(messages.getMessage("formTag.formBean", mapping.getName(), action));
			pageContext.setAttribute(Globals.EXCEPTION_KEY, e, PageContext.REQUEST_SCOPE);
			throw e;
		}

		// Calculate the required values
		beanName = mapping.getAttribute();
		beanScope = mapping.getScope();
		beanType = formBeanConfig.getType();
	}

	/**
	 * Returns true if this tag should render as xhtml.
	 */
	private boolean isXhtml() {
		return TagUtils.getInstance().isXhtml(this.pageContext);
	}
}
